using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Data.Schema.Extensibility;
using Microsoft.Data.Schema.SchemaModel;
using Microsoft.Data.Schema.ScriptDom.Sql;
using Microsoft.Data.Schema.Sql.SchemaModel;
using Microsoft.Data.Schema.Sql;
using Microsoft.Data.Schema.StaticCodeAnalysis;
using System.IO;
using System.Text.RegularExpressions;
using System.Linq;

namespace Neznayka
{
    /// <summary>
    /// This is a SQL rule which returns a warning message 
    /// whenever it finds a parameter name that is too short.
    /// </summary>

    [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
    [DataRuleAttribute(
        NeznaykaConstants.NameSpace,
        NeznaykaConstants.ParameterNameLengthRuleId,
        NeznaykaConstants.ResourceBaseName,
        NeznaykaConstants.ParameterNameLength_RuleName,
        NeznaykaConstants.CategoryVariableNaming,
        DescriptionResourceId = NeznaykaConstants.ParameterNameLength_ProblemDescription)]
    [SupportedElementType(typeof(ISqlFunction))]
    [SupportedElementType(typeof(ISqlTableValuedFunction))]
    [SupportedElementType(typeof(ISqlMultiStatementTableValuedFunction))]
    [SupportedElementType(typeof(ISqlProcedure))]
    public class ParameterNameLengthRule : StaticCodeAnalysisRule
    {
        #region Overrides
        /// <summary>
        /// Analyze the model element
        /// </summary>
        public override IList<DataRuleProblem> Analyze(DataRuleSetting ruleSetting, DataRuleExecutionContext context)
        {

            // (Re)-Load Environment settings
            List<DataRuleProblem> problems;
            SqlSchemaModel sqlSchemaModel;
            ISqlModelElement sqlElement;
            TSqlFragment sqlFragment;
            DMVRuleSetup.RuleSetup(context, out problems, out sqlSchemaModel, out sqlElement, out sqlFragment);

            // visitor to get the declarations of parameters
            ParameterDeclarationVisitor parameterDeclarationVisitor = new ParameterDeclarationVisitor();
            sqlFragment.Accept(parameterDeclarationVisitor);
            IEnumerable<ProcedureParameter> parameterDeclarations = parameterDeclarationVisitor.ParameterDeclarations;

            // Create problems for non builtin int variable found with a short name
            foreach (ProcedureParameter parameterDeclaration in parameterDeclarations)
            {
                //ExcludedVariableTypesForNameLengthRuleReadOnlyCollection
                //MinimumVariableNameLength
                string typeRegex = @"(?i:^(" + String.Join(@"|", DMVSettings.ExcludedParameterTypesForNameLengthRule) + @")$)";
                string typename = parameterDeclaration.DataType.Name.Identifiers[0].Value.ToLower();
                if (!Regex.IsMatch(typename, typeRegex, RegexOptions.None)
                     && parameterDeclaration.Name.Value.Length <= DMVSettings.MinimumParameterNameLength // name includes leading @
                    )
                {
                    DataRuleProblem problem = new DataRuleProblem(this,
                                                String.Format(CultureInfo.CurrentCulture, this.RuleProperties.Description, SqlRuleUtils.GetElementName(sqlSchemaModel, sqlElement)),
                                                sqlElement);

                    SqlRuleUtils.UpdateProblemPosition(problem, parameterDeclaration.StartOffset, parameterDeclaration.FragmentLength);
                    problems.Add(problem);
                }
            }


            return problems;
        }

        #endregion    
 
    }
}